1. ARRANQUE DE PROYECTO
-
Node.js Imprescindible tenerlo instalado.
-
CreateReactApp o Vitejs: Nos crean la estructura básica necesaria. Create React App, es lo que se llama un "bundler" es decir, que sirve para empaquetar la aplicación tanto en desarrollo (/src) como en producción (/dist), y el segundo, ya es más un entorno de desarrollo, ya que ofrece mayor variedad de herramientas. Nos quedaremos con que so nuestras herramientas de arranque de proyecto.
- Más información: La MEJOR forma de CREAR un Proyecto con REACT
-
cli: Durante el arranque, el desarrollo y la puesta en producción utilizaremos una serie de comandos desde la consola. Se puede acceder a un listado desde el árbol de la parte derecha de este tutorial.
-
package.json: Dependencias del proyecto. Este archivo lo usamos para llevarnos el proyecto, y no subir ficheros de desarrollo local (node_modules, por ejemplo). En otro equipo basta con hacer
npm install. -
package-lock.json: Dependencias de npm. Este fichero se crea solo, al hacer el
npm installtras meter el package.json en nestro proyecto.
2. COMPONENTES Y JSX
JSX es la sintaxis, y la extensión de ficheros de React. A través de esta sintaxis, crearemos los componentes, que son las piezas de nuestra interfaz de usuario. Los componentes deben retornar siempre algo. Puede ser HTML generado a través de funciones.
import React from 'react'
export const main = () => {
return (
<div>
...
</div>
)
}
Deben tener un <div> padre, para que la sintaxis no nos falle. Si no queremos compilar <div>´s adicionales, podemos usar los "fragments" que son etiquetas vacías (<> ... </>) que indican a la compilación que no hay una etiqueta contenedora para el HTML generado.
import React from 'react'
export const main = () => {
return (
<>
<div>
...
</div>
</>
)
}
Las "etiquetas HTML" de React, se pueden entender como una "mezcla entre HTML y JS". Esto nos permite encapsular componentes dentro de otros componentes, y pasarles valores de variables y/o constantes, como si fueran atributos de HTML. Para encapsular la sintaxis de JS, dentro de estas etiquetas, utilizamos corchetes {}
import { useContext } from 'react'
import { TaskContext } from '../../context/tasks/TaskContext'
export const TaskCard = ({ task }) => {
const {deleteTask} = useContext(TaskContext)
return (
<div>
<h1>
{task.title}
</h1>
<p>
{task.description}
</p>
<button onClick={()=>{deleteTask(task.id)}}>
Eliminar tarea
</button>
</div>
);
}
export default TaskCard
Una de las tareas que realizaremos habitualmente, como quizá ya hayamos llegado a deducir, es crear un componente que itere sobre otro que tenga a su vez encapsulado. Esto, compilará elementos HTML con atributos "id" únicos. En React, debemos utilizar la propiedad key para generar los id´s al compilar.
const TaskList = () => {
const { tasks } = useContext(TaskContext)
if (tasks.length === 0) {
return <h1> No se han definido tareas </h1>
}
return (
<div className='grid grid-cols-4 gap-4'>
{tasks.map((task) => (
<TaskCard key={task.id} task={task}/>
))}
</div>
)
}
3. PROPS
Las "props" son las propiedades que le podemos pasar a un componente. Normalmente harán referencia a un objeto que nos llegará como respuesta que recibiremos desde el servidor.
Podemos pasarle props para simular el objeto recibido...
export const UserCard = (props) => {
console.log();
return (
<div className="card">
<ul>
<li>{props.title}</li>
<li>{props.puesto}</li>
</ul>
</div>
);
}
export default UserCard;
... o podemos usar el "destructuring" de ES6 para pasar los parámetros.
export const UserCard = ({title,puesto}) => {
console.log();
return (
<div className="card">
<ul>
<li>{title}</li>
<li>{puesto}</li>
</ul>
</div>
);
}
-
Conviene instalar el módulo de node "propTypes", que nos permite:
- Asignar "fuerte tipado", obligando a pasar un tipo de valor al componente.
- Permite pasar valores por defecto (aunque el JS moderno de hoy en día también).
4. ESTILOS CSS
-
No se usa el atributo "class", si no el "className". El "style" para los estilos en línea se mantiene.
-
Las clases CSS, o los estilos en línea, se suelen asignar de manera habitual bajo condicionales IF, de manera dinámica.
5. GESTIÓN DE EVENTOS
-
En React asignamos los eventos como atributos en la sintaxis JSX (como si fueran atributos de HTML), lo cual facilita el trabajo.
-
Se utilizan funciones flecha, que guardamos con los nombres de los eventos, y que luego asignaremos a los eventos de los componentes.
export const TaskCard = ({ task }) => {
return (
<div>
<button onClick={()=>{sendTask(task.id)}}>
Eliminar tarea
</button>
</div>
);
}
-
Usamos siempre el objeto "event" o "e" para acceder a sus métodos y propiedades.
-
Todos los eventos en React empiezan por "on". Por ejemplo tenemos el onSubmit para los formularios.
-
Relevante saber que en el caso de "onSubmit", sustituira al atributo "action" de la etiqueta
<form>
import {useContext} from 'react'
import { TaskContext } from '../../context/tasks/TaskContext';
const TaskForm = () => {
const {
createTask,
title,
setTitle,
description,
setDescription
} = useContext(TaskContext);
const handleSubmit = (e)=> {
e.preventDefault();
createTask({title, description});
setTitle('');
setDescription('');
}
return (
<form onSubmit={handleSubmit}>
<input placeholder="Escribe tu tarea"
onChange={ (e)=> setTitle(e.target.value) }
value={title}
autoFocus
/>
<br />
<br />
<textarea
onChange={(e) => setDescription(e.target.value)}
placeholder="Escribe la descripción"
value={description}
></textarea>
<br />
<br />
<button>
Añadir tarea
</button>
<br />
<br />
</form>
)
}
export default TaskForm
En este código, además de mostrarse la gestión de los eventos, estamos empezando a hacer uso de los "contextos" que es donde separaremos la lógica de la aplicación, es decir, los métodos y las propiedades, que se definirán a través de los estados. De esta manera los componentes podrán llamar a la lógica de manera independiente unos de otros.
6. FETCH API
-
La API FETCH está en el navegador web (como la del DOM, u otras varias) y sirve para realizar peticiones asíncronas. La utilizaremos mucho en React y en frameworks de JavaScript modernos.
-
Fetch API: Docu mozilla
-
Recurso útil para pruebas: Json placeholder
7. MÓDULOS DE TERCEROS
- [React Icons](https://react-icons.github.io/react-icons): Página principal desde la que ver los iconos disponibles, y desde la que podemos copiar su nombre para incrustarlos como componentes en nuestra app. [En este enlace podemos ver cómo utilizar toda la librería](https://stackoverflow.com/questions/72275798/how-to-import-all-icons-in-material-design-from-react-icons).
- MUI: Librería de componentes Material Design de Google.
8. MÉTODOS PARA ARRAYS
- Método **map()**: Muy utilizado. Recibe una función callback como parámetro, que a su vez, recibe como parámetro un array que procesar. [REFERENCIA MÉTODO MAP EN DEVELOPERS.MOZILLA](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
- Otros métodos de uso habitual en React:
-
filter(): Genera un nuevo array partiendo del que se utiliza para ejecutar el método, y evita que uno o varios valores se copien a este nuevo array.
-
find(): Busca un elemento dentro del array sobre el que se ejecuta el método.
-
sort(): Ordena los elementos del array sobre el que se ejecuta el método.
-
reduce(): Comprime un array lo máximo posible, y lo devuelve en una variable dada como parámetro con un valor inicial. El valor que retorna es esta reducción del array.
-
9. HOOKS: USE STATE
-
Es difícil definir un hook, pero se puede decir que le da funcionalidades extra en nuestra app. Con las normas de cada hook, podemos hacer muchas cosas diferentes.
-
Hay que recordar la sintaxis de extracción de arrays.
-
El hook useState nos devuelve una variable y una función para modificar esa variable. Dado que esa variable contiene un array, usamos la sintaxis de extracción de arrays previamente mencionada, para extraer y a la vez definir.
-
Este hook determinará los "estados" de nuestro componente. Los estados equivaldrían a cómo se ve nuestro componente en el DOM. Entendamos que en React no podemos capturar elementos del DOM y pintarlos como queramos a través de una función de JavaScript (no podemos por ejemplo, crear operaciones matemáticas y pintar el resultado en el HTML). En React todo funciona con estos "estados".
10. HOOKS: USE EFFECT
-
Devuelve la ejecución, x veces, de una función pasada dada parámetro a este hook.
- Caso 1 de ejecución: Cada vez que se renderiza el componente
- Caso 2 de ejecución: Solo la primera vez que se renderiza el componente.
- Caso 3 de ejecución: Cuando le pasamos una "dependencia". La dependencia puede ser por ejemplo, un parámetro que le asigna el valor al hook useState (esto es complejillo de entender, es mejor verlo en la práctica, de momento con retener el concepto basta).
-
Este Hook determina el cambio de dos o más partes de la interfaz de usuario.
-
Utiliza valores que vengan desde el backend y determinan el comportamiento de la interfaz de usuario.
-
Viene muy bien utilizar la extensión React Developer tools. En la imagen se ve cómo con esta extensión podemos ver el árbol de componentes y sus respectivos estados.
-
En lo referente a la gestión de los estados, de momento nos vale con retener el concepto general, y como veremos luego, agrupar toda la lógica en lo que llamamos "contexto". No obstante aunque no se aborde en este curso de introducción, existen librerías de uso generalizado para la gestión de los estados, como REDUX.
11. USE CONTEXT
Hasta este punto, hemos visto que la sintaxis JSX nos permite insertar componentes dentro de otros, y pasar valores como parámetros. Frameworks como React se utilizan para crear aplicaciones de cierta complejidad, con lo cual, no podemos crear multitud de componentes que se pasen parámetros de unos a otros (a este mala praxis se le conoce como "prop drilling").
La idea es que los componentes de la interfaz, puedan pedir los datos y las funciones a un componente principal al que en React se le hace referencia con el nombre de "contexto".
Esto estaría mal, es el llamado "prop drilling".
Este es el concepto que se busca con la idea de "contexto".
-
El "estado" y su "comportamiento" en la interfaz de usuario, los determinamos a través de useState y useEffect, que son dos módulos del core de React. Tendremos que utilizar estos métodos para poder determinar el comportamiento dinámico de cada componente.
-
La cuestión es que hay varios componentes que pueden determinar el valor de los datos, a través de los mismos datos, por ello utilizamos un contexto. En este caso, es el contexto de las "tareas". Vamos a centralizar los métodos y propiedades relativos a las tareas en la carpeta /context/Task.jsx.
En la siguiente código, podemos ver el uso de useState y useEffect dentro de un "contexto".
import { createContext, useState, useEffect } from "react"
import { tasks as data } from '../../data/tasks'
export const TaskContext = createContext();
export const TaskContextProvider = (props) => {
const [tasks, setTasks] = useState([]);
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
useEffect(() => {
setTasks(data)
}, [])
const createTask = (task) => {
setTasks([...tasks, {
title: task.title,
id: tasks.length,
description: task.description
}])
}
const deleteTask = (taskId) => {
setTasks(tasks.filter(task => task.id !== taskId))
}
return (
<TaskContext.Provider value={{
tasks,
title,
setTitle,
description,
setDescription,
deleteTask,
createTask
}}>
{props.children}
</TaskContext.Provider>
)
}
Una vez definido el contexto, vamos a utilizar el objeto props de React para pasarle toda la capa lógica a lo que llamamos un "provider", el cual podemos utilizar una vez definido el contexto. Exportando el componente de contexto (<TaskContextProvider>), podremos encapsularlo dentro de la etiqueta principal <React>
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { TaskContextProvider } from './context/tasks/TaskContext'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<TaskContextProvider>
<App />
</TaskContextProvider>
</React.StrictMode>
)
Esto nos permitirá llamar a la lógica a través de la función useContext() desde los diferentes componentes, cumpliendo con lo que se mostraba en la imagen que hemos visto antes.
Los conceptos de este curso se ampliarán en otro documento relacionado a herramientas como REDUX.